package util;

/**
 * 使用3线程等待方法对外部Console程序进行操作的封装功能类
 * 本类为主要使用类
 * 
 * @author BKMMSC 金鸡独立
 * @version 1.0
 * @since 2014
 *
 */

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.PrintStream;

import util.*;

public class ExternalProgramUtil {

	/**
	 * runtime对象，用于执行exec方法并返回process对象
	 */
	public Runtime runtime=Runtime.getRuntime();
	/**
	 * 存放并与其他子线程共享用于操作外部程序的process对象
	 */
	public Process process;
	/**
	 * 请注意此字段！此字段将会更新并反馈目标程序的标准错误信息
	 */
	public String errorinfo;
	/**
	 * 请注意此字段！此字段将会更新并反馈目标程序的标准输出信息
	 */
	public String outputinfo;
	/**
	 * 用于随时监视目标程序标准错误流的子进程的实例，在本类实例化时被创建
	 */
	public ErrorStream es;
	/**
	 * 用于随时监视目标程序标准输出流的子进程的实例，在本类实例化时被创建
	 */
	public OutputStream os;
	/**
	 * 对目标程序进行标准输入操作的流对象，每次使用其进行手动输入时需要ps.flush()
	 */
	public PrintStream ps;

	/**
	 * 直接执行命令，返回不加处理的process，如果要使用该类，请实例化
	 * 
	 * @param command 执行的命令，cmd格式
	 * @return 未经处理的process对象
	 * @throws IOException 当指令错误或执行错误时
	 */
    public static Process pexe(String command) throws IOException{
		return Runtime.getRuntime().exec(command);
	}

	/**
	 * 构造方法之一，只有一个启动外部程序的文本，相当于Runtime.exec(exec);，但会对子进程和process进行初始化
	 * 
	 * @param exec 执行的命令，cmd格式
	 * @throws IOException 当指令错误或执行错误时
	 */
	public ExternalProgramUtil(String exec) throws IOException{
		process=runtime.exec(exec);
		es=new ErrorStream();
		os=new OutputStream();
		es.process=process;
		os.process=process;
		es.start();
		os.start();
		ps=new PrintStream(new BufferedOutputStream(process.getOutputStream()));
	}

	/**
	 * 得到目标程序的标准错误流线程
	 * 
	 * @return 返回目前的标准错误流线程对象
	 */
	public ErrorStream getEs() {
		return es;
	}

	/**
	 * 指定目标程序的标准错误流线程
	 * 
	 * @param es 要设置的标准错误流线程对象
	 */
	public void setEs(ErrorStream es) {
		this.es = es;
	}

	/**
	 * 得到目标程序的标准输出流线程
	 * 
	 * @return 返回目前的标准输出流线程对象
	 */
	public OutputStream getOs() {
		return os;
	}

	/**
	 * 指定目标程序的标准输出流线程
	 * 
	 * @param os 要设置的标准输出流线程对象
	 */
	public void setOs(OutputStream os) {
		this.os = os;
	}

	/**
	 * 向目标程序输入指定信息，使用本方法无需flush，本方法不自带换行
	 * 
	 * @param arg 要输入到目标成的的文本，请他类型请进行转换
	 */

	public void print(String arg){
		ps.print(arg);
		ps.flush();
	}

	/**
	 * 得到目标程序的标准错误流信息，调用此getter则不需要调用更新方法
	 * 
	 * @return 返回目前的标准错误流信息
	 */
	public String getErrorinfo() {
		this.updateerr();
		return errorinfo;
	}

	/**
	 * 得到目标程序的标准输出流信息，调用此getter则不需要调用更新方法
	 * 
	 * @return 返回目前的标准输出流信息
	 */
	public String getOutputinfo() {
		this.updateout();
		return outputinfo;
	}

	/**
	 * 向目标程序输入一个换行，使用本方法无需flush，本方法自带换行
	 * 
	 */
	public void println(){
		ps.println();
		ps.flush();
	}

	/**
	 * 向目标程序输入指定信息，使用本方法无需flush，本方法自带换行
	 * 
	 * @param arg 要输入到目标成的的文本，请他类型请进行转换
	 */
	public void println(String arg){
		ps.println(arg);
		ps.flush();
	}

	/**
	 * 对目标程序的标准错误流信息进行更新，使用对应的getter方法则不需要调用本方法
	 * 
	 */
	public void updateerr(){
		errorinfo=es.err;
	}

    /**
	 * 对目标程序的标准输出流信息进行更新，使用对应的getter方法则不需要调用本方法
	 * 
	 */
	public void updateout(){
		outputinfo=os.out;
	}

	/**
	 * 已过时！不建议使用！
	 * 关闭已经连接的3流，停止2个子线程，释放资源而不是等待它们被Java自行回收
	 * 不推荐使用，由于关闭线程存在死锁的危险性，具体原因可搜索：为什么不建议使用Thread.stop()方法
	 * 如果希望更安全地释放资源，可以使用本类的gc()方法启动Java垃圾回收器回收资源
	 * 使用前请先进行延时等待
	 * 
	 */
	@SuppressWarnings("deprecation")
	public void close(){
		es.stop();
		os.stop();
		ps.close();
		runtime=null;
		process=null;
		errorinfo=null;
		outputinfo=null;
		es=null;
		os=null;
		ps=null;
	}

	/**
	 * 启动Java自动垃圾回收器，更安全地关闭已经连接的3流，停止2个子线程，释放资源而不是等待它们被Java自行回收
	 * 请尽量调用本方法而不要使用stop()方法，这样可以避免死锁等问题并更安全地释放资源
	 * 使用前请先进行延时等待
	 * 
	 */
	public void gc(){
		es.interrupt();
		os.interrupt();
		runtime=null;
		process=null;
		errorinfo=null;
		outputinfo=null;
		es=null;
		os=null;
		ps=null;
	}
}
